//////////////////////////////////////////////////////////////////////////////////
//	 Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <wx/html/htmlwin.h>
#include <wx/imaglist.h>
#include "../common/MarkupSTL.h"
#include "rcmdapp.h"
#include "mainwnd.h"
#include "wirelesstab.h"
#include "searchpanel.h"
#include <algorithm>
#include "wirelessstatpanel.h"

enum cListColumns  { cListColumnSignalLevel, cListColumnMAC, cListColumnTimeInNetwork, cListColumnState, cListColumnTXRate, cListColumnRXRate, cListColumnRates };

enum cIDS
{
	ID_LIST=8120,
	ID_APSTAT,
	ID_ANYLIZE
};

bool	CWirelessTab::m_bSortAsc = true;

static SEARCHFIELD sf[]=
{
	{ cSearchTypeNumeric,	cListColumnSignalLevel,		_("Signal Strength")	},
	{ cSearchTypeString,	cListColumnMAC,				_("MAC")				},
	{ cSearchTypeNumeric,	cListColumnTimeInNetwork,	_("Time in network")	},
	{ cSearchTypeString,	cListColumnState,			_("State")				},
	{ cSearchTypeNumeric,	cListColumnTXRate,			_("Transmit (kbps)")	},
	{ cSearchTypeString,	cListColumnRXRate,			_("Receive (kbps)")		},
	{ cSearchTypeNumeric,	cListColumnRates,			_("Supported Rates")	},
};


BEGIN_EVENT_TABLE(CWirelessTab, wxPanel)
	EVT_LIST_COL_CLICK(ID_LIST, CWirelessTab::OnColumn)
END_EVENT_TABLE()


CWirelessTab::CWirelessTab(class wxWindow* pParent):wxPanel(pParent),
	m_lSearchResLine(SEARCH_NOT_FOUND), CSearchImpl<CWirelessTab>(*this)
{
	wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);

	m_pSearch = new CSearchPanel(this, this);
	sizer->Add(m_pSearch, 0, wxALL|wxEXPAND);

	m_nSortCol= cListColumnMAC;
	m_pList = new CLogCtrl<CWirelessTab>(this, ID_LIST);

	SetSearchListPtr(m_pList);

	sizer->Add(m_pList, 1, wxALL|wxEXPAND);

	for (size_t i=0;i<sizeof(sf)/sizeof(sf[0]);i++)
	{
		m_pList->InsertColumn( sf[i].iFieldID, sf[i].strLabel );
	}

	m_pList->SetColumnWidth( cListColumnSignalLevel,		120 );
	m_pList->SetColumnWidth( cListColumnMAC,				120 );
	m_pList->SetColumnWidth( cListColumnTimeInNetwork,		100 );
	m_pList->SetColumnWidth( cListColumnState,				100 );
	m_pList->SetColumnWidth( cListColumnTXRate,				100 );
	m_pList->SetColumnWidth( cListColumnRXRate,				120 );
	m_pList->SetColumnWidth( cListColumnRates,				200 );

	/*
	m_pAPWindow = new wxHtmlWindow(this,ID_APSTAT, wxDefaultPosition, wxSize(200,100), wxHW_SCROLLBAR_AUTO );
	sizer->Add(m_pAPWindow, 1, wxALL|wxEXPAND);
	*/


	m_pStatPanel = NULL;

	/*
	m_pStatPanel = new CWirelessStatPanel(this);
	sizer->Add(m_pStatPanel, 0, wxALL|wxEXPAND);
	*/

	m_pAnylizeWindow = new wxHtmlWindow(this,ID_ANYLIZE, wxDefaultPosition, wxSize(200,100), wxHW_SCROLLBAR_AUTO );
	sizer->Add(m_pAnylizeWindow, 0, wxALL|wxEXPAND);

	SetSizer(sizer);

	ShowAnalyze("");

	ShowApData("");

	m_pImageList = new wxImageList(16, 16);

	wxImage icnTmp;
	if ( icnTmp.LoadFile(wxGetApp().GetImageDir()+wxT("wf_00.png"),   wxBITMAP_TYPE_PNG) )
	{
		m_pImageList->Add( icnTmp );
	}

	if ( icnTmp.LoadFile(wxGetApp().GetImageDir()+wxT("wf_00_24.png"),   wxBITMAP_TYPE_PNG) )
	{
		m_pImageList->Add( icnTmp );
	}

	if ( icnTmp.LoadFile(wxGetApp().GetImageDir()+wxT("wf_25_49.png"),   wxBITMAP_TYPE_PNG) )
	{
		m_pImageList->Add( icnTmp );
	}

	if ( icnTmp.LoadFile(wxGetApp().GetImageDir()+wxT("wf_50_74.png"),   wxBITMAP_TYPE_PNG) )
	{
		m_pImageList->Add( icnTmp );
	}

	if ( icnTmp.LoadFile(wxGetApp().GetImageDir()+wxT("wf_75_100.png"),   wxBITMAP_TYPE_PNG) )
	{
		m_pImageList->Add( icnTmp );
	}

	m_pList->SetImageList(m_pImageList, wxIMAGE_LIST_SMALL);
	m_pList->SetImageList(m_pImageList, wxIMAGE_LIST_STATE);
}

CWirelessTab::~CWirelessTab(void)
{
}

//IGUIBind
void CWirelessTab::OnResponse(const COMMANDRESPONSE& resp)
{
	ShowApData( resp.strXML );
	ShowAnalyze( resp.strXML );

	if ( resp.strXML.empty() ) return;

	m_entriesBeforeFilter.erase(m_entriesBeforeFilter.begin(), m_entriesBeforeFilter.end());

	GUIBIND bindOut;
	bool bHaveAccess = wxGetApp().GetMainWnd()->GetLogic().GetBind( bindOut, cCmdARPTable );
	
	CMarkupSTL	doc;

	if ( doc.SetDoc(resp.strXML.c_str()) )
	{
		if ( doc.FindChildElem(WRLS_XML_TAG_ASSOC_LST) )
		{
			doc.IntoElem();

			while ( doc.FindChildElem(WRLS_XML_TAG_ENTRY) )
			{
				WIRELESSCLIENT wrls;

				RTSTRING strMAC = doc.GetChildData();
				wrls.strMAC = wxString::FromAscii( strMAC.c_str() );

				if ( bHaveAccess )
				{
					COMMANDRESPONSE resp;
					resp.code = cCmdSetDetectedWirelessMAC;
					resp.strData = strMAC;

					bindOut.GetBinding()->OnResponse( resp );
				}

				wrls.strRateset = wxString::FromAscii( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_RATESET).c_str() );
				wrls.strIdleTime = wxString::FromAscii( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_IDLE).c_str() );
				wrls.strTimeInNetwork = wxString::FromAscii( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_INNETW).c_str() );
				wrls.strState = wxString::FromAscii( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_STATE).c_str() );
				wrls.stTXPkts = (size_t)atol( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_STATE).c_str() );
				wrls.stTXFailPkts = (size_t)atol( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_TXFAIL).c_str() );
				wrls.stRXUcastPkts = (size_t)atol( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_RX_UCAST).c_str() );
				wrls.stRXMBCastPkts = (size_t)atol( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_RX_MBCAST).c_str() );
				wrls.stTXRate = (size_t)atol( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_TX_RATE).c_str() );
				wrls.stRXRate = (size_t)atol( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_RX_RATE).c_str() );
				wrls.nSignalStrength = atol( doc.GetChildAttrib(WRLS_XML_ATTR_CLNT_SIGN_STRNGTH).c_str() );

				m_entriesBeforeFilter.push_back(wrls);
			}

			doc.OutOfElem();
		}
	}

	ProcessData();
}

void CWirelessTab::Reset()
{
	m_entriesBeforeFilter.erase( m_entriesBeforeFilter.begin(), m_entriesBeforeFilter.end() );
	ProcessData();
}


//////////////////////////////////////////////////////////////////////////
//Data
void CWirelessTab::ProcessData()
{
	try
	{
		ResetSearchPos();

		DoFilter();
		DoSort();

		((CLogCtrl<CWirelessTab>*)m_pList)->DataChanged(true);
	}
	catch(...)
	{
	}
}


//////////////////////////////////////////////////////////////////////////
//Val
wxString CWirelessTab::FieldToString( int column, const WIRELESSCLIENT& entry)
{
	wxString str;

	try
	{
		switch(column)
		{
			case cListColumnSignalLevel:
				str = wxString::Format(wxT("%u"), entry.nSignalStrength);
			break;

			case cListColumnMAC:
				str = entry.strMAC;
			break;

			case cListColumnTimeInNetwork:
			{
				str = entry.strTimeInNetwork;
			}
			break;

			case cListColumnState:
				str = entry.strState;
			break;

			case cListColumnTXRate:
				str = wxString::Format(wxT("%u"), entry.stTXRate);
			break;

			case cListColumnRXRate:
				str = wxString::Format(wxT("%u"), entry.stRXRate);
			break;


			case cListColumnRates:
				str = entry.strRateset;
			break;

			default:
				assert(0);
			break;
		}
	}
	catch (...)
	{

	}

	return str;
}

int	CWirelessTab::GetItemColumnImage(long item, long column, wxWindowID id/*=wxID_ANY*/)
{
	int nRes(-1);

	if ( 0==column )
	{
		WIRELESSCLIENT& entry = m_entries[item];

		if ( entry.nSignalStrength<=0 )
		{
			nRes = 0;
		}
		else
		if ( entry.nSignalStrength<=24 )
		{
			nRes = 1;
		}
		else
		if ( entry.nSignalStrength<=49 )
		{
			nRes = 2;
		}
		else
		if ( entry.nSignalStrength<=74 )
		{
			nRes = 3;
		}
		else
		{
			nRes = 4;
		}
	}

	return nRes;
}

wxString CWirelessTab::GetItemText(long item, long column, wxWindowID id)
{
	wxString str;

	try
	{
		WIRELESSCLIENT& entry = m_entries[item];
		str = FieldToString( column, entry);
	}
	catch(...)
	{
	}

	return str;
}

//////////////////////////////////////////////////////////////////////////
//Search
void CWirelessTab::GetSearchFields(SEARCHFIELD*& sfRes, size_t& sz)
{
	sfRes = sf;
	sz = sizeof(sf)/sizeof(sf[0]);
}


//////////////////////////////////////////////////////////////////////////
//Sort
struct CSortHelper
{
	CSortHelper(int col, bool bSortAsc):m_col(col), m_bSortAsc(bSortAsc) {}

	bool operator() (const WIRELESSCLIENT& a, const WIRELESSCLIENT& b)
	{
		bool bRes(false);

		switch (m_col)
		{
			case cListColumnSignalLevel:
			bRes = a.nSignalStrength<b.nSignalStrength;
			break;

			case cListColumnMAC:
			bRes = a.strMAC<b.strMAC;
			break;

			case cListColumnTimeInNetwork:
			bRes = a.strTimeInNetwork<b.strTimeInNetwork;
			break;

			case cListColumnState:
			bRes = a.strState<b.strState;
			break;

			case cListColumnTXRate:
			bRes = a.stTXRate<b.stTXRate;
			break;

			case cListColumnRXRate:
			bRes = a.stRXRate<b.stRXRate;
			break;

			case cListColumnRates:
			bRes = a.strRateset<b.strRateset;
			break;
		}

		return m_bSortAsc?bRes:!bRes;
	}

private:
	int			 m_col;
	bool		 m_bSortAsc;
};


void CWirelessTab::DoSort()
{
	CSortHelper sorter(m_nSortCol, m_bSortAsc);
	std::sort( m_entries.begin(), m_entries.end(), sorter);
}

//////////////////////////////////////////////////////////////////////////
//Filter
void CWirelessTab::OnFilterChanged()
{
	ProcessData();
}

void CWirelessTab::DoFilter()
{
	wxString strVal;

	m_entries.erase( m_entries.begin(), m_entries.end() );

	for(size_t i=0;i<m_entriesBeforeFilter.size();i++)
	{
		bool bValid(true);

		for (size_t j=0;j<sizeof(sf)/sizeof(sf[0]);j++)
		{
			strVal = FieldToString( sf[j].iFieldID, m_entriesBeforeFilter[i] );

			if ( !m_pSearch->Match(sf[j], strVal) )
			{
				bValid = false;
				break;
			}
		}

		if ( bValid )
		{
			m_entries.push_back( m_entriesBeforeFilter[i] );
		}
	}
}

//////////////////////////////////////////////////////////////////////////
//Wnd Events
void CWirelessTab::OnColumn(wxListEvent& ev)
{
	m_bSortAsc=!m_bSortAsc;

	m_nSortCol = ev.m_col;

	DoSort();

	((CLogCtrl<CWirelessTab>*)m_pList)->DataChanged();
}


//////////////////////////////////////////////////////////////////////////
//AP Data
void CWirelessTab::ShowApData(const RTSTRING& strData)
{
	bool bShow(false);

	if (m_pStatPanel)
	{
		m_pStatPanel->ShowStats( strData );

		GetSizer()->FitInside(this);
		GetSizer()->Layout();
	}
}

//////////////////////////////////////////////////////////////////////////
//Analyze
void CWirelessTab::ShowAnalyze( const RTSTRING& strData )
{
	bool bProblemFound(false);

	int nOrder = 0;

	wxString strTemplate(wxT("<html><body>%s</body></html>"));
	wxString str;

	CMarkupSTL	doc;

	if ( doc.SetDoc(strData.c_str()) )
	{
		if ( doc.FindChildElem(WRLS_XML_TAG_STATUS) )
		{
			std::string strTmp = doc.GetChildAttrib(WRLS_XML_ATTR_ISUP);

			if ( strTmp=="1" || strTmp=="true" )
			{
				str+=wxT("<center><b><font size='4'>");
				str+=_("Wireless Security and Optimization Tips");
				str+=wxT("</font></b></center>");

				str+=wxT("<table>");

				str+=wxT("<table border='0' style='border-collapse: collapse' cellspacing='0' cellpadding='2' width='100%'>");
				str+=wxT("<tr bgcolor='#84CAF9'><th align='left'><b>");
				str+=_("Problem");
				str+=wxT("</b></th><th></th><th align='left'><b>");
				str+=_("How to fix it");
				str+=wxT("</b></th></tr>");

				std::string strWepstatus = doc.GetChildAttrib(WRLS_XML_ATTR_WEPSTATUS);
				std::string strWPAstatus = doc.GetChildAttrib(WRLS_XML_ATTR_WPA_AUTH);

				if ( strWepstatus=="0" &&
					std::string::npos!=strWPAstatus.find("Disabled") )
				{
					wxString  strLabel = _("Authentication disabled, Your wireless router may be accessed by anyone");
					str+=BuildTableLine(strLabel,
					_("Open router web configuration. Locate router wireless security settings. Change Network Authentication from Open to WPA2-PSK or other WPA based security according to router user guide."), nOrder);

					bProblemFound = true;
				}
				else
				if ( std::string::npos!=strWPAstatus.find("Disabled") )
				{
					wxString  strLabel = _("Weak WEP Encryption Used");
						str+=BuildTableLine(strLabel,
							_("Open router web configuration. Locate router wireless security settings. Change Network Authentication from Open to WPA2-PSK or other WPA based security according to router user guide."), nOrder);

					bProblemFound = true;
				}

				str+=wxT("</table>");
			}
			else
			{
				str+=wxT("<center><b><font size='4'>");
				str+=_("Access Point is down");
				str+=wxT("</font></b></center>");

				bProblemFound = true;
			}
		}
	}

	m_pAnylizeWindow->SetPage( wxString::Format(strTemplate,str.c_str()) );
	m_pAnylizeWindow->Show( bProblemFound );

	GetSizer()->FitInside(this);
	GetSizer()->Layout();
}

wxString CWirelessTab::BuildTableLine(const wxString& strProblem,
										 const wxString& strSolution, int& nOrder)
{
	wxString str;

	if ( (nOrder%2)!=0)
	{
		str+=wxT("<tr bgcolor='#F0F0F0'>");
	}
	else
	{
		str+=wxT("<tr>");
	}

	str+=wxT("<td width=300><img src='");
	str+=wxGetApp().GetImageDir()+wxT("perfomance_error.png");
	str+=wxT("'>&nbsp;<b>");

	str+=strProblem;

	str+=wxT("</b></td><td></td>");
	str+=wxT("<td>");

	str+=strSolution;

	str+=wxT("</td>");
	str+=wxT("</tr>");

	++nOrder;

	return str;
}

/*
wxString CWirelessTab::BuildStatTableLine( CMarkupSTL& doc, const char* szXMLATTR,
										  const wxString& strValName, int& nOrder, bool& bShow )
{
	wxString str;

	std::string strVal = doc.GetChildAttrib(szXMLATTR);

	if ( !strVal.empty() )
	{
		bShow = true;

		if ( (nOrder%2)!=0)
		{
			str+=wxT("<tr bgcolor='#F0F0F0'>");
		}
		else
		{
			str+=wxT("<tr>");
		}

		str+=wxT("<td>");
		str+=strValName;
		str+=wxT("</td>");

		str+=wxT("<td>");
		str+=wxString::FromAscii( strVal.c_str() );
		str+=wxT("</td>");

		str+=wxT("</tr>");

		++nOrder;
	}

	return str;
}


wxString CWirelessTab::BuildStatTable(class CMarkupSTL& doc)
{
	wxString str;
	bool bShow(false);

	int nOrder = 0;

	str+=wxT("<table>");
	str+=wxT("<table border='0' style='border-collapse: collapse' cellspacing='0' cellpadding='2' width='100%'>");
	str+=BuildStatTableLine(doc, "SSID", _("SSID"), nOrder, bShow);

	str+=wxT("</table>");

	return bShow?str:wxT("");
}
*/

wxString CWirelessTab::GetLog()
{
	wxString strStatus, strVal;

	if ( wxGetApp().GetMainWnd()->GetPropStorage().GetEnableWirelessLog() )
	{
		strStatus = _("Wireless");
		strStatus+=wxT(": ");

		bool bFound(false);

		for(size_t i=0;i<m_entriesBeforeFilter.size();i++)
		{
			wxString strLine;

			for (size_t j=0;j<sizeof(sf)/sizeof(sf[0]);j++)
			{
				if ( !strLine.empty() )
				{
					strLine+=wxT(", ");
				}

				strLine+= sf[j].strLabel;
				strLine+= wxT(": ");
				strLine+= FieldToString( sf[j].iFieldID, m_entriesBeforeFilter[i] );

				bFound = true;
			}

			strStatus+=strLine;
			strStatus+=wxT(". ");
		}

		if ( !bFound )
		{
			strStatus = _("No wireless connections detected");
		}
	}

	return strStatus;
}